﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using CustomTypes.Interfaces;
using Mono.Cecil;

namespace devtm.AutoMapper.TemplateAdd.Models
{
    
    [CLSCompliant(false)]
    public class NamespaceBox : TreeViewItem
    {


        public event EventHandler<SelectedEventArgs> Selected;

        internal static byte[] imgClass162 = devtm.AutoMapper.Properties.Resources.Class162.GetBytes();
        internal static byte[] imgNamespace = devtm.AutoMapper.Properties.Resources.Namespace.GetBytes();        

        private bool _loaded = false;
        private Predicate<TypeDefinition> predicate;
        private AssemblyBox _root;

        #region Ctor

        public NamespaceBox()
        {

            Items.SortDescriptions.Add(new System.ComponentModel.SortDescription("MyName", System.ComponentModel.ListSortDirection.Ascending));

        }

        public NamespaceBox(string[] @namespace, int index, AssemblyBox root, Predicate<TypeDefinition> predicate)
            : this()
        {

            this.predicate = predicate;
            this._root = root;

            if (index < @namespace.Length)
            {

                MyName = @namespace[index];

                ContextTitle = new ContainerHeader() { Label = MyName, ImageSource = imgNamespace };
                Header = new HeaderCtrl() { Context = ContextTitle };
                Index = index;

                Namespace = "";

                for (int i = 0; i <= index; i++)
                {
                    if (!string.IsNullOrEmpty(Namespace))
                        Namespace += ".";

                    Namespace += @namespace[i];
                }


                index++;
                if (index < @namespace.Length)
                {
                    NamespaceBox cc = new NamespaceBox(@namespace, index, _root, predicate);
                    AddChild(cc);
                }

            }

        }

        #endregion
        

        internal NamespaceBox GetItem(TypeElement source)
        {

            string Namespace = source.Namespace;

            foreach (NamespaceBox item in this.Items)
            {

                NamespaceBox i = item.GetItem(source);
                if (i != null)
                    return i;

            }

            return null;

        }

        internal NamespaceBox GetNamespace(string[] nn1, ref int index, IAssemblyDescriptor assembly)
        {
            string n = nn1[index];
            NamespaceBox retour = null;

            foreach (NamespaceBox item in this.Items)
                if ((item.MyName as string) == n)
                {
                    index++;
                    if (index < nn1.Length)
                    {
                        NamespaceBox r2 = item.GetNamespace(nn1, ref index, assembly);
                        if (r2 != null)
                        {
                            retour = r2;
                            break;
                        }
                    }
                }

            if (retour == null)
                retour = this;

            return retour;

        }

        internal void Insert(string[] @namespace, int index, IAssemblyDescriptor assembly)
        {
            NamespaceBox retour = this;

            if (index < @namespace.Length)
            {
                string n = @namespace[index];

                foreach (NamespaceBox item in this.Items)
                    if ((item.MyName as string) == n)
                    {
                        index++;
                        if (index < @namespace.Length)
                        {
                            retour = item.GetNamespace(@namespace, ref index, assembly);
                            break;
                        }
                    }
            }

            if (index < @namespace.Length)
            {
                NamespaceBox nn = new NamespaceBox(@namespace, index, _root, predicate);                                   
                retour.AddChild(nn);
            }

        }

        //internal string Name { get; set; }

        internal ContainerHeader ContextTitle { get; set; }


        protected override void OnMouseMove(System.Windows.Input.MouseEventArgs e)
        {
            base.OnMouseMove(e);

            if (!_loaded)            
                LoadItems();

        }

        public void LoadItems()
        {

            if (_root.includeType)
            {
                HashSet<string> h = new HashSet<string>() { Namespace };

                if (!Namespace.Contains("."))
                    h.Add(string.Empty);

                var l = _root.assembly.GetTypes(predicate, h).OrderBy(c => c.Name).ToList();

                foreach (var item in l)
                {
                    TypeBox b = new TypeBox(_root, item);
                    this.AddChild(b);
                }
            }
            
            _loaded = true;

            foreach (TreeViewItem item in this.Items)
                if (item is NamespaceBox)
                    (item as NamespaceBox).LoadItems();

        }
       

        protected override void OnSelected(System.Windows.RoutedEventArgs e)
        {
            base.OnSelected(e);

            if (!_loaded)
                LoadItems();

            _root.Select(this);

        }                   

        private T GetParent<T>()
            where T : FrameworkElement
        {

            FrameworkElement i = this.Parent as FrameworkElement;

            while (!(i is T) && i != null)         
                i = i.Parent as FrameworkElement;
                
            return i as T;

        }


        public int Index { get; set; }

        public string MyName { get; set; }

        public string Namespace { get; set; }


        internal void Select(AutoMapper.TemplateAdd.Models.TypeBox typeBox)
        {           

            if (Selected != null)
                Selected(typeBox, new SelectedEventArgs(typeBox.Type));
        }

        internal bool ShowType()
        {

            var selectedType = _root.selectedType;
            var selectedNamespace = _root.Namespace;
     
            LoadItems();

            IsExpanded = true;

            foreach (var item in Items)
            {

                NamespaceBox n = item as NamespaceBox;
                if (n != null)
                {

                    if (selectedType != null && selectedType.Namespace.StartsWith(n.Namespace))                    
                        return n.ShowType();                    

                }
                else
                {
                    TypeBox t = item as TypeBox;
                    if (t != null)
                    {
                        if (selectedType.FullName == t.Type.FullName)
                        {
                            t.IsSelected = true;
                            return true;
                        }
                    }
                }

            }

            return false;
        }

        internal bool ShowNamespace()
        {

            var selectedType = _root.selectedType;
            var selectedNamespace = _root.Namespace;

            IsExpanded = true;

            foreach (var item in Items)
            {

                NamespaceBox n = item as NamespaceBox;

                if (n != null)
                {
                    if (selectedNamespace != null)
                    {

                        if (selectedNamespace == n.Namespace)
                        {
                            n.IsSelected = true;
                            return true;
                        }

                        else if (selectedNamespace.StartsWith(n.Namespace))                        
                            return n.ShowNamespace();

                    }
                }
            }


            return false;
        }
    
    }
}
